Skip to content

refactor(hawk): consume runtime-owned Eyrie transport selection#77

Merged
Patel230 merged 7 commits into
mainfrom
codex/hawk-eyrie-boundary-v3
Jun 29, 2026
Merged

refactor(hawk): consume runtime-owned Eyrie transport selection#77
Patel230 merged 7 commits into
mainfrom
codex/hawk-eyrie-boundary-v3

Conversation

@Patel230

Copy link
Copy Markdown
Contributor

Summary

  • make Hawk consume Eyrie runtime selection and transport resolution instead of rebuilding provider decisions locally
  • update review and config flows to use runtime-owned transport resolution
  • align Hawk internal config wrappers and tests with the Eyrie-owned selection model
  • update external/eyrie submodule pointer to the new runtime commit

Verification

  • go test ./cmd ./internal/engine -count=1
  • go test -race ./cmd ./internal/engine -count=1
  • golangci-lint run ./cmd ./internal/engine ./internal/config ./internal/bridge/sight ./internal/types ./internal/multiagent --timeout=5m
  • validated on clean branch against external/eyrie at commit 967ab85

@Patel230
Patel230 merged commit ee5243a into main Jun 29, 2026
18 checks passed
@Patel230
Patel230 deleted the codex/hawk-eyrie-boundary-v3 branch June 29, 2026 11:18
Patel230 added a commit that referenced this pull request Jul 11, 2026
* refactor(hawk): consume runtime-owned eyrie transport selection

* refactor(hawk): remove dead config cache helper

* style(hawk): normalize runtime gateway wrappers

* fix(hawk): preserve setup status hint contract

* test(hawk): isolate version globals in cmd tests

* fix(hawk): preserve explicit model selection boundary

* fix(hawk): require explicit model before chat
Patel230 added a commit that referenced this pull request Jul 16, 2026
* refactor(hawk): consume runtime-owned eyrie transport selection

* refactor(hawk): remove dead config cache helper

* style(hawk): normalize runtime gateway wrappers

* fix(hawk): preserve setup status hint contract

* test(hawk): isolate version globals in cmd tests

* fix(hawk): preserve explicit model selection boundary

* fix(hawk): require explicit model before chat
Patel230 added a commit that referenced this pull request Jul 20, 2026
eyrie changes merged via PR #77 (not the closed neutral-host-defaults PR):
host-neutral defaults, provider.json + categories.json legacy migration,
poolside adapter. Repin to actual main tip.
Patel230 added a commit that referenced this pull request Jul 20, 2026
…107)

* feat: polish config and chat UI

* refactor(gateway): consolidate eyrie access behind Provider interface

Single gateway package owns all eyrie imports via a hawk-owned Provider
interface. Config, routing, and engine wiring delegate through it, giving a
swappable provider seam (verified by a stub test), centralized type
translation, and one boundary that the audit rules can guard. The submodule
pointer moves to the neutral-host-defaults eyrie commit that makes the
credential-store default host-neutral.

* perf(gateway): cache shared default gateway with sync.Once

Stateless model-lookup helpers (DefaultModel, Find, RecommendedModel, ...)
previously built a fresh eyrie engine on every call. eyrie's Engine reloads
its catalog and provider config from disk on each method call, so a single
long-lived gateway returns identical freshness — construct it once.

Keeps the defaultGateway(ctx) signature unchanged; ctx still flows through
to every data call via the helpers.

* refactor(gateway): split Provider into role interfaces

Provider is now a composition of 7 role interfaces (Generator,
NativeCompactor, ModelCatalog, CredentialManager, SelectionManager,
GatewayInspector, CatalogMaintenance). Gateway embeds the roles directly
so every existing caller (session_factory, translateProvider, config,
routing) keeps working via the composite Provider.

Drops 4 unused methods (Resolve, bare Preflight, ApplyGatewayEnvironment,
MigrateProviderSecretsContext) that grep confirmed had no callers.

provider_stub_test.go now builds Gateway with only the Generator role,
proving stubs can depend on a narrow facet.

* test: migrate eyrie imports to gateway boundary

23 test files now import gateway instead of eyrie directly:
- 22 fixture-only files use gateway.SetDefaultStore/MapStore/etc
- session_factory_test.go uses gateway.Selection

Gateway re-exports the credential test fixtures (SetDefaultStore,
DefaultStore, MapStore, AccountForEnv, HasSecret) so tests inject
fixtures through the single boundary.

11 genuine keepers stay exempt (they test eyrie itself: engine
construction, event translation, Provider stub, catalog/config/registry
internals). audit_test.go is a string-literal false positive.

* chore: repin eyrie submodule to neutral-defaults commit

go.mod eyrie pseudo-version now points at cb1efad (the Phase-0 commit
that makes the credential-store service name and config-dir default
host-neutral). go.sum refreshed.

Verified build + test pass both with go.work (local replace) and
GOWORK=off (CI/upstream path using the version string).

* refactor(gateway): narrow translateProvider + make identity init explicit

- translateProvider now holds only Generator + NativeCompactor (the two
  roles it uses) instead of the full Provider.
- Extract the SetServiceName('hawk') side-effect out of New into a
  documented, sync.Once-guarded declareHawkIdentity so it is explicit
  and runs exactly once.
- Repin eyrie to 637ce7a (adds the legacy provider.json migration).

* chore: repin eyrie to include legacy categories.json migration

* chore: repin eyrie to merged main (b2cab57, PR #77)

eyrie changes merged via PR #77 (not the closed neutral-host-defaults PR):
host-neutral defaults, provider.json + categories.json legacy migration,
poolside adapter. Repin to actual main tip.

* fix(engine): route self-heal shell through the Bash safety stack

SelfHealer.runCommand ran model-generated shell via a raw
exec.CommandContext(ctx, sh, -c, command) that bypassed every guard
the Bash tool enforces (IsDestructiveCommand, IsSuspicious,
CommandReferencesSensitivePath, sandbox.WrapCommand). A jailbroken model
could read ~/.hawk/provider.json or fork-bomb from a fix attempt.

Now rejects commands that reference sensitive paths or are flagged
destructive, returning a clear error before exec. Added tests for both
rejection paths.

* fix(tool): background bash process group + flatten nested goroutine

Background bash had three issues:
1. ran on the request ctx, so the task was killed when the HTTP/Tool
   request timed out. Now uses an independent context.
2. no Setpgid → Process.Kill() only killed the parent bash, leaving
   grandchildren (e.g. ) orphaned. Now sets
   SysProcAttr{Setpgid:true} and stop() kills the whole group via
   kill(-pgid, SIGKILL).
3. nested goroutine (a goroutine that spawned another to watch
   shellCtx.Done) was redundant. Flattened into a single outer
   goroutine that races cmd.Wait against shellCancel via a channel.

Applied the same Setpgid fix to the foreground Bash tool path.

* refactor(gateway): declare identity first, dedup provider converter

- declareHawkIdentity() now runs as the FIRST line of gateway.New,
  before eyrieengine.New, matching its documented invariant that no
  credential read happens under the host-neutral default service name.
- Added gateway.BuildCustomGateways as the single shared conversion
  loop; config.eyrie_engine and engine.session_factory now delegate to
  it so a new CustomProviderConfig field only wires once.
- Fixed stale Gateway doc comment (no longer claims to embed Provider).

* refactor(session): remove deprecated stored fields, read through sub-services

The Session struct carried three deprecated fields (DeploymentRouting,
ContainerExecutor, ContainerRequired) that were dual-written with the
sub-service instances and could drift out of sync on ReattachTransport.

Now read through to the sub-services via getter methods:
- DeploymentRouting() -> ChatService.DeploymentRouting()
- ContainerExecutor()/ContainerRequired() -> ToolService.*

Setters updated to write to the sub-service (source of truth). Also
fixed SetGLMThinkingEnabled to update the ChatService (it previously
only touched the legacy field, which the chat path never read).

Deleted the unused ListLiveEngineModels wrapper.

* refactor(settings): remove dead fields + adapt tests

Removed 6 unused Settings fields: MinimalMode, PaginatorMarginTop,
PaginatorMarginBottom, AutoDarkTheme, AutoLightTheme, CustomHeaders.
All were inert in production (only referenced by their own tests).

Deleted IsMinimalMode helper and the MinimalMode/CustomHeaders tests;
replaced with a DeploymentRouting merge test. MergeSettings already
skips nil pointer overrides, so no behavior change there.

* refactor(daemon): split handleChat god-function + observe client disconnect

Extracted streamSSE and writeJSONResponse helpers from the 251-line
handleChat. The SSE loop now select-s on r.Context().Done() so a
client disconnect releases the session and bails immediately, instead
of pushing events to a dead connection.

Verified sanitizer lock: Sanitize takes RLock only to snapshot 3 config
fields into locals, then releases — clean snapshot pattern, no bug.

* fix(low): hardening nits across icons, snapshot, multiagent

- icons: Glyph/ASCII/Nerd no longer panic on unknown names (return ),
  preventing a registry load order issue from crashing the TUI.
- snapshot: tests reverted to original Track(message) signature.
- multiagent: git/go helper commands now accept and use the worker's
  ctx so they abort on mission cancellation instead of running to
  completion with context.Background().

* feat(types): alias internal/types DTOs to hawk-core-contracts/llm

Hawk's conversation DTOs (EyrieMessage, EyrieResponse, ChatOptions, ...)
and StreamResult are now type aliases of the canonical port contract, the
same definitions eyrie/client/core already aliases. Hawk's product
vocabulary is now defined exactly once.

StreamResult's Close() and NewStreamResult constructor now resolve to the
contract; the few call sites updated to llm.NewStreamResult.

Co-Authored-By: Claude <noreply@anthropic.com>

* feat(gateway): collapse translateProvider conversions to identity

Engine conversation DTOs are now the canonical contract types, so the
gateway's field-mapping helpers collapse: toEngineMessages/toEngineTools/
toEngineToolChoice/fromEngineResponse/fromEngineRoute/fromEngineUsage are
identity, and fromEngineEvent only translates the event-type vocabulary
(engine 'content_delta'->hawk 'content'). toEngineRequest/ChatOptions
mapping remains, since request shaping is still real work.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: improve error handling, thread safety, and tool validation

- Add mutex to Session for thread-safe model/provider access
- Centralize HTTP/WebSocket tool result parsing
- Add required argument validation for MCP tools
- Expand tilde-user references in bash tool normalization
- Add unrecognized engine event logging in gateway
- Reorder imports for consistency

* chore: update submodule pointers to latest feat/llm-port-contract commits

---------

Co-authored-by: Claude <noreply@anthropic.com>
Patel230 added a commit that referenced this pull request Jul 21, 2026
* feat: polish config and chat UI

* refactor(gateway): consolidate eyrie access behind Provider interface

Single gateway package owns all eyrie imports via a hawk-owned Provider
interface. Config, routing, and engine wiring delegate through it, giving a
swappable provider seam (verified by a stub test), centralized type
translation, and one boundary that the audit rules can guard. The submodule
pointer moves to the neutral-host-defaults eyrie commit that makes the
credential-store default host-neutral.

* perf(gateway): cache shared default gateway with sync.Once

Stateless model-lookup helpers (DefaultModel, Find, RecommendedModel, ...)
previously built a fresh eyrie engine on every call. eyrie's Engine reloads
its catalog and provider config from disk on each method call, so a single
long-lived gateway returns identical freshness — construct it once.

Keeps the defaultGateway(ctx) signature unchanged; ctx still flows through
to every data call via the helpers.

* refactor(gateway): split Provider into role interfaces

Provider is now a composition of 7 role interfaces (Generator,
NativeCompactor, ModelCatalog, CredentialManager, SelectionManager,
GatewayInspector, CatalogMaintenance). Gateway embeds the roles directly
so every existing caller (session_factory, translateProvider, config,
routing) keeps working via the composite Provider.

Drops 4 unused methods (Resolve, bare Preflight, ApplyGatewayEnvironment,
MigrateProviderSecretsContext) that grep confirmed had no callers.

provider_stub_test.go now builds Gateway with only the Generator role,
proving stubs can depend on a narrow facet.

* test: migrate eyrie imports to gateway boundary

23 test files now import gateway instead of eyrie directly:
- 22 fixture-only files use gateway.SetDefaultStore/MapStore/etc
- session_factory_test.go uses gateway.Selection

Gateway re-exports the credential test fixtures (SetDefaultStore,
DefaultStore, MapStore, AccountForEnv, HasSecret) so tests inject
fixtures through the single boundary.

11 genuine keepers stay exempt (they test eyrie itself: engine
construction, event translation, Provider stub, catalog/config/registry
internals). audit_test.go is a string-literal false positive.

* chore: repin eyrie submodule to neutral-defaults commit

go.mod eyrie pseudo-version now points at cb1efad (the Phase-0 commit
that makes the credential-store service name and config-dir default
host-neutral). go.sum refreshed.

Verified build + test pass both with go.work (local replace) and
GOWORK=off (CI/upstream path using the version string).

* refactor(gateway): narrow translateProvider + make identity init explicit

- translateProvider now holds only Generator + NativeCompactor (the two
  roles it uses) instead of the full Provider.
- Extract the SetServiceName('hawk') side-effect out of New into a
  documented, sync.Once-guarded declareHawkIdentity so it is explicit
  and runs exactly once.
- Repin eyrie to 637ce7a (adds the legacy provider.json migration).

* chore: repin eyrie to include legacy categories.json migration

* chore: repin eyrie to merged main (b2cab57, PR #77)

eyrie changes merged via PR #77 (not the closed neutral-host-defaults PR):
host-neutral defaults, provider.json + categories.json legacy migration,
poolside adapter. Repin to actual main tip.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant